package com.cea.papyrus.diagram.sequence.ui.dialogs;

import java.util.Iterator;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.uml2.uml.AcceptCallAction;
import org.eclipse.uml2.uml.AcceptEventAction;
import org.eclipse.uml2.uml.Action;
import org.eclipse.uml2.uml.ActionExecutionSpecification;
import org.eclipse.uml2.uml.AddVariableValueAction;
import org.eclipse.uml2.uml.BroadcastSignalAction;
import org.eclipse.uml2.uml.CallBehaviorAction;
import org.eclipse.uml2.uml.CallOperationAction;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.OpaqueAction;
import org.eclipse.uml2.uml.SendObjectAction;
import org.eclipse.uml2.uml.SendSignalAction;
import org.eclipse.uml2.uml.TestIdentityAction;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.UnmarshallAction;
import org.eclipse.uml2.uml.ValueSpecificationAction;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.commands.UMLElementCreateCommand;
import com.cea.papyrus.core.editor.CommandStackUtils;

public class ExecutionSpecificationActionGenericActionTreeSelectionDialog extends Dialog {
	
	protected ActionExecutionSpecification execSpec;
	
	protected Action action;
	
	protected EClass kindOfAction;
	protected String kindOfActionName;
	
	protected Composite composite;
	protected Button newButton;
	protected Label label;
	protected Tree SFTree;
	
	/**
	 * The Menu to show all kinds of possible Behavior.
	 */
	private Menu menu;

	/**
	 * Various menu items.
	 */
	private MenuItem
	opaqueActionItem,
	acceptCallActionItem,
	acceptEventActionItem,
	addVariableValueActionItem,
	broadcastSignalActionItem,
	callBehaviorActionItem,
	callOperationActionItem,
	sendObjectActionItem,
	sendSignalActionItem,
	testIdentityActionItem,
	unmarshallActionItem,
	valueSpecificationActionItem;

	/**
	 * Associated selection listeners.
	 */
	private SelectionListener 
	opaqueActionItemListener,
	acceptCallActionItemListener,
	acceptEventActionItemListener,
	addVariableValueActionItemListener,
	broadcastSignalActionItemListener,
	callBehaviorActionItemListener,
	callOperationActionItemListener,
	sendObjectActionItemListener,
	sendSignalActionItemListener,
	testIdentityActionItemListener,
	unmarshallActionItemListener,
	valueSpecificationActionItemListener;
	
	public ExecutionSpecificationActionGenericActionTreeSelectionDialog (Shell parent, ActionExecutionSpecification execSpec) {
		super (parent);
		this.execSpec = execSpec;
		// add the resize ability to the window
		setShellStyle(SWT.RESIZE | super.getShellStyle());
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
	 */
	protected Control createDialogArea(Composite parent){
		composite = (Composite) super.createDialogArea(parent);
			
		label = new Label(composite, SWT.NONE);
		label.setText("Select an existing action or create a new Action :");
		label.setLayoutData(new GridData());
		
		newButton = new Button(composite, SWT.NONE);
		newButton.setText("New Action :");
		newButton.setLayoutData(new GridData(200, 25));
		//add an additional menu to the add Button
		createMenuForNewButton();
		
		SFTree = new Tree(composite, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL);

		final Interaction enclosingInteraction = execSpec.getEnclosingInteraction();
		// get owned Actions
		Iterator<Action> iter = enclosingInteraction.getActions().iterator();
		while(iter.hasNext()){
			Action currentAction = iter.next();
			if (currentAction instanceof Action) {
				TreeItem actionItem = new TreeItem(SFTree, SWT.SINGLE);
				actionItem.setText(currentAction.getName());
				actionItem.setData(currentAction);
				actionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(currentAction));
			}
		}
			
		SFTree.setLayoutData(new GridData(550, 300));
		
		SFTree.addSelectionListener(new SelectionListener() {
			public void widgetSelected(SelectionEvent e){
				TreeItem[] selection = SFTree.getSelection();
				if(selection[0].getData() instanceof Action) {
					action = (Action) selection[0].getData() ;
				}
			}

			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
		
		
		newButton.addMouseListener(new MouseListener(){
			public void mouseDoubleClick(MouseEvent e) {
			}

			public void mouseDown(MouseEvent e) {
			}

			public void mouseUp(MouseEvent e) {

				if(!menu.isDisposed())
					menu.setVisible(true);
				}

		});
		
		return composite;
	}
	
	/**
	 * Adds an additional menu to the addButton. So user can choose which type of trigger to create.
	 */
	private void createMenuForNewButton(){
		menu = new Menu (newButton);
		
		// add OpaqueAction menu item
		opaqueActionItem = new MenuItem (menu, SWT.PUSH);
		opaqueActionItem.setText("OpaqueAction");
		opaqueActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(OpaqueAction.class, null));
		opaqueActionItem.addSelectionListener(opaqueActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.OPAQUE_ACTION));
		
		// add AcceptCallAction menu item
		acceptCallActionItem = new MenuItem (menu, SWT.PUSH);
		acceptCallActionItem.setText("AcceptCallAction");
		acceptCallActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(AcceptCallAction.class, null));
		acceptCallActionItem.addSelectionListener(acceptCallActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.ACCEPT_CALL_ACTION));
		
		// add AcceptEventAction menu item
		acceptEventActionItem = new MenuItem (menu, SWT.PUSH);
		acceptEventActionItem.setText("AcceptEventAction");
		acceptEventActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(AcceptEventAction.class, null));
		acceptEventActionItem.addSelectionListener(acceptEventActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.ACCEPT_EVENT_ACTION));
		
		// add AddVariableValueAction menu item
		addVariableValueActionItem = new MenuItem (menu, SWT.PUSH);
		addVariableValueActionItem.setText("AddVariableValueAction");
		addVariableValueActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(AddVariableValueAction.class, null));
		addVariableValueActionItem.addSelectionListener(addVariableValueActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.ADD_VARIABLE_VALUE_ACTION));
		
		// add BroadcastSignalAction menu item
		broadcastSignalActionItem = new MenuItem (menu, SWT.PUSH);
		broadcastSignalActionItem.setText("BroadcastSignalAction");
		broadcastSignalActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(BroadcastSignalAction.class, null));
		broadcastSignalActionItem.addSelectionListener(broadcastSignalActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.BROADCAST_SIGNAL_ACTION));
		
		// add CallBehaviorAction menu item
		callBehaviorActionItem = new MenuItem (menu, SWT.PUSH);
		callBehaviorActionItem.setText("CallBehaviorAction");
		callBehaviorActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(CallBehaviorAction.class, null));
		callBehaviorActionItem.addSelectionListener(callBehaviorActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.CALL_BEHAVIOR_ACTION));
				
		// add CallOperationAction menu item
		callOperationActionItem = new MenuItem (menu, SWT.PUSH);
		callOperationActionItem.setText("CallOperationAction");
		callOperationActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(CallOperationAction.class, null));
		callOperationActionItem.addSelectionListener(callOperationActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.CALL_OPERATION_ACTION));
		
		// add SendObjectAction menu item
		sendObjectActionItem = new MenuItem (menu, SWT.PUSH);
		sendObjectActionItem.setText("SendObjectAction");
		sendObjectActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(SendObjectAction.class, null));
		sendObjectActionItem.addSelectionListener(sendObjectActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.SEND_OBJECT_ACTION));
		
		// add SendSignalAction menu item
		sendSignalActionItem = new MenuItem (menu, SWT.PUSH);
		sendSignalActionItem.setText("SendSignalAction");
		sendSignalActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(SendSignalAction.class, null));
		sendSignalActionItem.addSelectionListener(sendSignalActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.SEND_SIGNAL_ACTION));

		// add TestIdentityAction menu item
		testIdentityActionItem = new MenuItem (menu, SWT.PUSH);
		testIdentityActionItem.setText("TestIdentityAction");
		testIdentityActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(TestIdentityAction.class, null));
		testIdentityActionItem.addSelectionListener(testIdentityActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.TEST_IDENTITY_ACTION));
		
		// add UnmarshallAction menu item
		unmarshallActionItem = new MenuItem (menu, SWT.PUSH);
		unmarshallActionItem.setText("UnmarshallAction");
		unmarshallActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(UnmarshallAction.class, null));
		unmarshallActionItem.addSelectionListener(unmarshallActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.UNMARSHALL_ACTION));
		
		// add ValueSpecificationAction menu item
		valueSpecificationActionItem = new MenuItem (menu, SWT.PUSH);
		valueSpecificationActionItem.setText("ValueSpecificationAction");
		valueSpecificationActionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(ValueSpecificationAction.class, null));
		valueSpecificationActionItem.addSelectionListener(valueSpecificationActionItemListener = 
			new AddElementSelectionListener(UMLPackage.Literals.VALUE_SPECIFICATION_ACTION));
		
		newButton.setMenu (menu);
	}
	
	/**
	 * Disposes of the composite
	 */
	public void removeListeners(){

		if((opaqueActionItem != null) && !opaqueActionItem.isDisposed())
			opaqueActionItem.removeSelectionListener(opaqueActionItemListener);
		if((acceptCallActionItem != null) && !acceptCallActionItem.isDisposed())
			acceptCallActionItem.removeSelectionListener(acceptCallActionItemListener);
		if((acceptEventActionItem != null) && !acceptEventActionItem.isDisposed())
			acceptEventActionItem.removeSelectionListener(acceptEventActionItemListener);
		if((addVariableValueActionItem != null) && !addVariableValueActionItem.isDisposed())
			addVariableValueActionItem.removeSelectionListener(addVariableValueActionItemListener);
		if((broadcastSignalActionItem != null) && !broadcastSignalActionItem.isDisposed())
			broadcastSignalActionItem.removeSelectionListener(broadcastSignalActionItemListener);
		if((callBehaviorActionItem != null) && !callBehaviorActionItem.isDisposed())
			callBehaviorActionItem.removeSelectionListener(callBehaviorActionItemListener);
		if((callOperationActionItem != null) && !callOperationActionItem.isDisposed())
			callOperationActionItem.removeSelectionListener(callOperationActionItemListener);
		if((sendObjectActionItem != null) && !sendObjectActionItem.isDisposed())
			sendObjectActionItem.removeSelectionListener(sendObjectActionItemListener);
		if((sendSignalActionItem != null) && !sendSignalActionItem.isDisposed())
			sendSignalActionItem.removeSelectionListener(sendSignalActionItemListener);
		if((testIdentityActionItem != null) && !testIdentityActionItem.isDisposed())
			testIdentityActionItem.removeSelectionListener(testIdentityActionItemListener);
		if((unmarshallActionItem != null) && !unmarshallActionItem.isDisposed())
			unmarshallActionItem.removeSelectionListener(unmarshallActionItemListener);
		if((valueSpecificationActionItem != null) && !valueSpecificationActionItem.isDisposed())
			valueSpecificationActionItem.removeSelectionListener(valueSpecificationActionItemListener);
	}
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
	 */
	protected void configureShell(Shell shell) {
	      super.configureShell(shell);
	      shell.setText(execSpec.getName()+": Action Selection");
	}

	/**
	 * Returns the elements to import.
	 * 
	 * @return 
	 */
	public Action getResult(){
		return action;
	}

	/**
	 * Listener for the menu items.
	 */
	public class AddElementSelectionListener implements SelectionListener {

		/**
		 * Constructor with given class.
		 * 
		 * @param elementClass Class
		 */
		public AddElementSelectionListener(EClass elementClass){
			this.elementClass = elementClass;
		}

		/**
		 * Stored Class.
		 */
		public EClass elementClass;

		/**
		 * Does nothing.
		 * 
		 * @param e SelectionEvent.
		 */
		public void widgetDefaultSelected(SelectionEvent e) {
		}

		/**
		 * What to do when item selected depending on the type of Behavior we want to associate a BehavioredClassifier to.
		 * 
		 * @param e SelectionEvent.
		 */
		public void widgetSelected(SelectionEvent e) {
			assert execSpec != null : "Passed argument is null";
			assert execSpec instanceof ActionExecutionSpecification : "Passed argument is not a ActionExecutionSpecification";
			
			Interaction enclosingInteraction = execSpec.getEnclosingInteraction();
			// creation command
			final UMLElementCreateCommand command = 
				new UMLElementCreateCommand(elementClass.getInstanceClass(), enclosingInteraction);
			
			CommandStack commandStack = CommandStackUtils.getCommandStack();
			if(commandStack!= null) {
				commandStack.execute(command);
			}

			Action newAction = (Action) command.getElement();
			// add the new OpaqueBehavior
			TreeItem actionItem = new TreeItem(SFTree, SWT.SINGLE);
			actionItem.setText(newAction.getName());
			actionItem.setData(newAction);
			actionItem.setImage(PapyrusPlugin.UML_LABEL_PROVIDER.getImage(newAction));
			
			SFTree.setSelection(actionItem);
			action = (Action) actionItem.getData();
		}
	}

}